package com.py.framework.scheduler.job;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;

import com.alibaba.fastjson.JSON;
import com.py.framework.scheduler.common.JobConstants;
import com.py.framework.scheduler.job.factory.DefaultJobFactory;
import com.py.framework.scheduler.job.factory.DisallowConcurrentJobFactory;

/**
 * 任务调度管理器, 实现任务的动态操作
 * @author Leegern
 * @date   2018年5月7日
 */
public class JobManager {

    /** 调度管理器注入工厂bean **/
    private SchedulerFactory schedulerFactory; 


	/**
	 * @return the schedulerFactory
	 */
	public SchedulerFactory getSchedulerFactory() {
		return schedulerFactory;
	}

	/**
	 * @param schedulerFactory the schedulerFactory to set
	 */
	public void setSchedulerFactory(SchedulerFactory schedulerFactory) {
		this.schedulerFactory = schedulerFactory;
	}

	
	/**
     * 添加任务
     * @param job
     * @throws SchedulerException
     */
    public void addJob(Job job) throws SchedulerException, ClassNotFoundException {
        if (job == null || StringUtils.isBlank(job.getJobId())) {
        	return;
        }
        if(StringUtils.isBlank(job.getCronExpression()) && null == job.getSimpleExpression()) {
        	 return;
        }
        if(StringUtils.isBlank(job.getJobName())) {
        	job.setJobName(JobConstants.JobName.JOB_DEFAULT_NAME);
        }
        if(null == job.getSimpleExpression()) {
            addCronJob(job);
        } else {
            addSimpleJob(job);
        }
    }
    
    /**
     * 更新任务
     * @param job
     * @throws SchedulerException
     * @throws ClassNotFoundException 
     */
    public void updateJob(Job job) throws SchedulerException, ClassNotFoundException {
    	if (job == null || StringUtils.isBlank(job.getJobId())) {
        	return;
        }
        if(StringUtils.isBlank(job.getCronExpression()) && null == job.getSimpleExpression()) {
        	 return;
        }
        if(StringUtils.isBlank(job.getJobName())) {
        	job.setJobName(JobConstants.JobName.JOB_DEFAULT_NAME);
        }
        Scheduler scheduler = schedulerFactory.getScheduler();
        JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
        // 判断是否存在任务
        if (scheduler.checkExists(jobKey)) {
        	scheduler.deleteJob(jobKey);
        }
        if(null == job.getSimpleExpression()) {
            addCronJob(job);
        } else {
            addSimpleJob(job);
        }
    }
    
    /**
     * 更新job时间表达式
     * @param job
     * @throws SchedulerException
     */
    public void updateJobCron(Job job) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(
                job.getJobId(), job.getJobGroup());
        CronTrigger trigger = (CronTrigger) schedulerFactory.getScheduler().getTrigger(triggerKey);
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression())).build();
        schedulerFactory.getScheduler().rescheduleJob(triggerKey, trigger);
    }

    /**
     * 更新job时间表达式
     * @param job
     * @throws SchedulerException
     */
    public void updateJobSimple(Job job) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(
                job.getJobId(), job.getJobGroup());
        SimpleTrigger trigger = (SimpleTrigger) schedulerFactory.getScheduler().getTrigger(triggerKey);
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule())
                .startAt(job.getSimpleExpression()).build();
        schedulerFactory.getScheduler().rescheduleJob(triggerKey, trigger);
    }

    /**
     * 获取所有计划中的任务列表
     * @return
     * @throws SchedulerException
     */
    public List<Job> getAllJob() throws SchedulerException {
        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = schedulerFactory.getScheduler().getJobKeys(matcher);
        List<Job> jobList = new ArrayList<>();
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = schedulerFactory.getScheduler().getTriggersOfJob(jobKey);
            for (Trigger trigger : triggers) {
                Job job = new Job();
                job.setJobId(jobKey.getName());
                job.setJobGroup(jobKey.getGroup());
                Trigger.TriggerState triggerState = schedulerFactory.getScheduler().getTriggerState(trigger.getKey());
                job.setJobStatus(triggerState.name());
                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    job.setCronExpression(cronExpression);
                }
                jobList.add(job);
            }
        }
        return jobList;
    }

    /**
     * 获取所有正在运行的job
     * @return
     * @throws SchedulerException
     */
    public List<Job> getRunningJob() throws SchedulerException {
        List<JobExecutionContext> executingJobs = schedulerFactory.getScheduler().getCurrentlyExecutingJobs();
        List<Job> jobList = new ArrayList<>(executingJobs.size());
        for (JobExecutionContext executingJob : executingJobs) {
            Job job = new Job();
            JobDetail jobDetail = executingJob.getJobDetail();
            JobKey jobKey = jobDetail.getKey();
            Trigger trigger = executingJob.getTrigger();
            job.setJobName(jobKey.getName());
            job.setJobGroup(jobKey.getGroup());
            Trigger.TriggerState triggerState = schedulerFactory.getScheduler().getTriggerState(trigger.getKey());
            job.setJobStatus(triggerState.name());
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpression = cronTrigger.getCronExpression();
                job.setCronExpression(cronExpression);
            }
            jobList.add(job);
        }
        return jobList;
    }

    /**
     * 暂停job
     * @param scheduleJob
     * @throws SchedulerException
     */
    public void pauseJob(Job scheduleJob) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(scheduleJob.getJobId(), scheduleJob.getJobGroup());
        schedulerFactory.getScheduler().pauseJob(jobKey);
    }

    /**
     * 恢复job
     * @param job
     * @throws SchedulerException
     */
    public void resumeJob(Job job) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
        schedulerFactory.getScheduler().resumeJob(jobKey);
    }

    /**
     * 删除job
     * @param scheduleJob
     * @throws SchedulerException
     */
    public void deleteJob(Job scheduleJob) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(scheduleJob.getJobId(), scheduleJob.getJobGroup());
        schedulerFactory.getScheduler().deleteJob(jobKey);

    }

    /**
     * 立即执行job
     * @param job
     * @throws SchedulerException
     */
    public void triggerJob(Job job) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(job.getJobId(), job.getJobGroup());
        schedulerFactory.getScheduler().triggerJob(jobKey);
    }
    
    /**
     * 启动所有定时任务
     * @throws SchedulerException 
     */
    public void startJobs() throws SchedulerException {  
    	if (! schedulerFactory.getScheduler().isShutdown()) {
    		schedulerFactory.getScheduler().start();
    	}
    }  

    /** 
     * 关闭所有定时任务 
     * @throws SchedulerException 
     */  
    public void shutdownJobs() throws SchedulerException {  
    	if (! schedulerFactory.getScheduler().isShutdown()) {  
    		schedulerFactory.getScheduler().shutdown(); 
        } 
    }
    
    /**
     * 调度任务是否已开启
     * @throws SchedulerException 
     */
    public boolean isStarted() throws SchedulerException {
    	return schedulerFactory.getScheduler().isStarted();
    }
    
    /**
     * 添加 cron表达式任务
     * @param job
     * @throws SchedulerException
     * @throws ClassNotFoundException
     */
    private void addCronJob(Job job) throws SchedulerException, ClassNotFoundException {
        //根据任务id和任务组Id创建触发器key
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), job.getJobGroup());
        //获取触发器对象
        CronTrigger trigger = (CronTrigger) schedulerFactory.getScheduler().getTrigger(triggerKey);
        // 不存在，创建一个
        if (null == trigger) {
            JobDetail jobDetail = JobBuilder.newJob(job.isConcurrent() ? DefaultJobFactory.class : DisallowConcurrentJobFactory.class)
                    .withIdentity(job.getJobId(), job.getJobGroup()).build();
            jobDetail.getJobDataMap().put(JobConstants.SCHEDULER_NAME, JSON.toJSONString(job));
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(
                            job.getCronExpression())).build();
            schedulerFactory.getScheduler().scheduleJob(jobDetail, trigger);
            // 启动  
            if (! schedulerFactory.getScheduler().isShutdown()) {  
            	schedulerFactory.getScheduler().start();  
            } 
        } else {
            updateJobCron(job);
        }
    }

    /**
     * 添加简单时间 表达式任务
     * @param job
     * @throws SchedulerException
     * @throws ClassNotFoundException
     */
    private void addSimpleJob(Job job) throws SchedulerException {
        //根据任务id和任务组Id创建触发器key
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), job.getJobGroup());
        //获取触发器对象
        SimpleTrigger trigger = (SimpleTrigger) schedulerFactory.getScheduler().getTrigger(triggerKey);
        // 不存在，创建一个
        if (null == trigger) {
            JobDetail jobDetail = JobBuilder.newJob(job.isConcurrent() ? DefaultJobFactory.class : DisallowConcurrentJobFactory.class)
                    .withIdentity(job.getJobId(), job.getJobGroup()).build();
            jobDetail.getJobDataMap().put(JobConstants.SCHEDULER_NAME, JSON.toJSONString(job));
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule())
                    .startAt(job.getSimpleExpression()).build();
            schedulerFactory.getScheduler().scheduleJob(jobDetail, trigger);
            // 启动  
            if (! schedulerFactory.getScheduler().isShutdown()) {  
            	schedulerFactory.getScheduler().start();  
            } 
        } else {
            updateJobSimple(job);
        }
    }
}